"""
数据库连接管理
"""
import time

import redis
from sqlalchemy import create_engine
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker, Session
from sqlalchemy.pool import StaticPool
from app.config import settings
from app.models.database import Base
from loguru import logger


class DatabaseManager:
    """数据库管理器"""

    def __init__(self):
        self.engine = None
        self.async_engine = None
        self.SessionLocal = None
        self.AsyncSessionLocal = None
        self.redis_client = None

    def init_database(self):
        """初始化数据库连接"""
        try:
            # 同步数据库引擎
            self.engine = create_engine(
                settings.database_url,
                poolclass=StaticPool,
                pool_pre_ping=True,
                echo=settings.debug
            )

            # 异步数据库引擎
            async_url = settings.database_url.replace("postgresql://", "postgresql+asyncpg://")
            self.async_engine = create_async_engine(
                async_url,
                pool_pre_ping=True,
                echo=settings.debug
            )

            # 会话工厂
            self.SessionLocal = sessionmaker(
                autocommit=False,
                autoflush=False,
                bind=self.engine
            )

            self.AsyncSessionLocal = sessionmaker(
                class_=AsyncSession,
                autocommit=False,
                autoflush=False,
                bind=self.async_engine
            )

            # 创建表
            Base.metadata.create_all(bind=self.engine)
            logger.info("数据库初始化成功")

        except Exception as e:
            logger.error(f"数据库初始化失败: {e}")
            raise

    # connect.py 修改init_redis方法
    def init_redis(self):
        """增强Redis连接初始化"""
        try:
            # 获取配置中的密码（优先使用单独设置的密码）
            password = settings.redis_password

            # 调试信息
            logger.info(f"Redis连接调试信息:")
            logger.info(f"  URL: {settings.redis_url}")
            logger.info(f"  密码: '{password}'")
            logger.info(f"  密码长度: {len(password) if password else 0}")
            logger.info(f"  密码类型: {type(password)}")

            # 打印密码的每个字符（用于调试特殊字符）
            if password:
                logger.info(f"  密码字符: {[c for c in password]}")

            # 尝试不同的连接方式
            connection_success = False

            # 方式1: 直接使用参数连接（避免URL中的特殊字符问题）
            try:
                logger.info("尝试方式1: 直接参数连接")
                self.redis_client = redis.Redis(
                    host="localhost",
                    port=6379,
                    db=0,
                    username="default",
                    password=password,
                    decode_responses=True,
                    socket_connect_timeout=10,
                    socket_timeout=10
                )
                # 测试连接
                result = self.redis_client.ping()
                logger.info(f"方式1连接成功! Ping结果: {result}")
                connection_success = True
            except Exception as e1:
                logger.warning(f"方式1失败: {e1}")

                # 方式2: 使用URL连接
                try:
                    logger.info("尝试方式2: URL连接")
                    pool = redis.ConnectionPool.from_url(
                        settings.redis_url,
                        decode_responses=True,
                        socket_connect_timeout=10,
                        socket_timeout=10,
                        socket_keepalive=True,
                        max_connections=20,
                        health_check_interval=10
                    )
                    self.redis_client = redis.Redis(connection_pool=pool)
                    # 测试连接
                    result = self.redis_client.ping()
                    logger.info(f"方式2连接成功! Ping结果: {result}")
                    connection_success = True
                except Exception as e2:
                    logger.warning(f"方式2失败: {e2}")

                    # 方式3: 无用户名连接
                    try:
                        logger.info("尝试方式3: 无用户名连接")
                        self.redis_client = redis.Redis(
                            host="localhost",
                            port=6379,
                            db=0,
                            password=password,
                            decode_responses=True,
                            socket_connect_timeout=10,
                            socket_timeout=10
                        )
                        # 测试连接
                        result = self.redis_client.ping()
                        logger.info(f"方式3连接成功! Ping结果: {result}")
                        connection_success = True
                    except Exception as e3:
                        logger.error(f"方式3失败: {e3}")
                        raise Exception(f"所有连接方式都失败: 方式1={e1}, 方式2={e2}, 方式3={e3}")

            if not connection_success:
                raise Exception("Redis连接失败")



        except Exception as e:
            logger.error(f"Redis连接初始化失败: {e}")
            logger.error("可能的原因:")
            logger.error("1. Redis Docker容器网络配置问题")
            logger.error("2. Redis配置文件中的bind设置限制了连接")
            logger.error("3. Redis protected-mode开启，需要密码或绑定地址")
            logger.error("4. 防火墙或iptables规则阻止连接")
            logger.error("5. Redis最大连接数限制")
            logger.warning("Redis连接失败，系统将在无缓存模式下运行")
            logger.info("系统功能不受影响，只是没有缓存加速")
            self.redis_client = None
    def get_db_session(self) -> Session:
        """获取同步数据库会话"""
        return self.SessionLocal()

    def get_async_db_session(self) -> AsyncSession:
        """获取异步数据库会话"""
        return self.AsyncSessionLocal()

    def get_redis_client(self) -> redis.Redis:
        """获取Redis客户端"""
        if self.redis_client is None:
            logger.warning("Redis客户端不可用，返回None")
        return self.redis_client

    def close_connections(self):
        """关闭所有连接"""
        if self.engine:
            self.engine.dispose()
        if self.async_engine:
            self.async_engine.dispose()
        if self.redis_client:
            self.redis_client.close()
        logger.info("数据库连接已关闭")


# 全局数据库管理器实例
db_manager = DatabaseManager()


def get_database():
    """依赖注入：获取同步数据库会话"""
    db = db_manager.get_db_session()
    try:
        yield db
    finally:
        db.close()


async def get_async_database():
    """依赖注入：获取异步数据库会话"""
    async with db_manager.get_async_db_session() as session:
        yield session


def get_redis():
    """依赖注入：获取Redis客户端"""
    return db_manager.get_redis_client()


# 数据库健康检查
def check_database_health() -> bool:
    """检查数据库连接健康状态"""
    try:
        with db_manager.get_db_session() as db:
            db.execute("SELECT 1")
        return True
    except Exception as e:
        logger.error(f"数据库健康检查失败: {e}")
        return False


def check_redis_health() -> bool:
    """检查Redis连接健康状态"""
    try:
        redis_client = db_manager.get_redis_client()
        if redis_client is None:
            logger.error("Redis客户端不可用，健康检查失败")
            return False
        redis_client.ping()
        return True
    except Exception as e:
        logger.error(f"Redis健康检查失败: {e}")
        return False
